#pragma once

#ifndef __HWINMENU_H__
#define __HWINMENU_H__

#include "hwindef.h"
#include "hwinmessage.h"
#include "hwinhandle.h"
#include "hwincomponent.h"

namespace harlinn
{
    namespace windows
    {
        class Control;
        class Menu;
        class MenuItems;
        class MenuItem : public Component
        {
            friend class Control;
            friend class Menu;
            friend class MenuItems;

            std::shared_ptr<BitmapHandle> bitmap;
            std::shared_ptr<BitmapHandle> checkedBitmap;
            std::shared_ptr<BitmapHandle> uncheckedBitmap;

            bool checked;
            bool isDefault;
            bool disabled;
            bool grayed;
            bool highlighted;


            bool menuBarBreak;
            bool menuBreak;
            bool ownerDraw;

            std::weak_ptr<Menu> parentMenu;
        public:
            typedef Component Base;

            HWIN_EXPORT MenuItem( );
            HWIN_EXPORT ~MenuItem( );

            HWIN_EXPORT std::shared_ptr<MenuItems> ParentMenuItems() const;
            HWIN_EXPORT std::shared_ptr<Menu> ParentMenu() const;
            HWIN_EXPORT int IndexOf( ) const;

            HWIN_EXPORT std::shared_ptr<BitmapHandle> Bitmap() const;
            HWIN_EXPORT MenuItem& SetBitmap(std::shared_ptr<BitmapHandle> theBitmap);

            HWIN_EXPORT std::shared_ptr<BitmapHandle> CheckedBitmap() const;
            HWIN_EXPORT MenuItem& SetCheckedBitmap(std::shared_ptr<BitmapHandle> theCheckedBitmap);

            HWIN_EXPORT std::shared_ptr<BitmapHandle> UncheckedBitmap() const;
            HWIN_EXPORT MenuItem& SetUncheckedBitmap(std::shared_ptr<BitmapHandle> theUncheckedBitmap);

            HWIN_EXPORT bool IsChecked() const;
            HWIN_EXPORT MenuItem& SetChecked(bool value = true);

            HWIN_EXPORT bool IsDefault() const;
            HWIN_EXPORT MenuItem& SetDefault(bool value = true);

            HWIN_EXPORT bool IsDisabled() const;
            HWIN_EXPORT MenuItem& SetDisabled(bool value = true);

            HWIN_EXPORT bool IsEnabled() const;
            HWIN_EXPORT MenuItem& SetEnabled(bool value = true);
            
            HWIN_EXPORT bool IsGrayed() const;
            HWIN_EXPORT MenuItem& SetGrayed(bool value = true);

            HWIN_EXPORT bool IsHighlighted() const;
            HWIN_EXPORT MenuItem& SetHighlighted(bool value = true);

            boost::signals2::signal<void ( MenuItem* sender )> OnClick;
            boost::signals2::signal<void ( MenuItem* sender, MEASUREITEMSTRUCT& measureItemStruct )> OnMeasureItem;
            boost::signals2::signal<void ( MenuItem* sender, DRAWITEMSTRUCT& drawItemStruct )> OnDrawItem;
        protected:
            HWIN_EXPORT virtual MenuItem& DoOnAdd();
            HWIN_EXPORT virtual MenuItem& DoOnRemove();
            HWIN_EXPORT virtual const MenuItem& UpdateMenuItem() const;
            HWIN_EXPORT virtual const MenuItem& InitializeMenuItemInfo(MENUITEMINFO& info) const;
            HWIN_EXPORT virtual void DoOnMenuCommand(Message& message);
            HWIN_EXPORT virtual void DoOnMeasureItem(MEASUREITEMSTRUCT& measureItemStruct);
            HWIN_EXPORT virtual void DoOnDrawItem(DRAWITEMSTRUCT& drawItemStruct);

        };


        class TextMenuItem : public MenuItem
        {
            String text;
        public:
            typedef MenuItem Base;

            HWIN_EXPORT TextMenuItem(const wchar_t* theText);
            HWIN_EXPORT TextMenuItem(const String& theText);

            HWIN_EXPORT TextMenuItem& SetText(const wchar_t* theText);
            HWIN_EXPORT TextMenuItem& SetText(const String& theText);
            HWIN_EXPORT const String& Text() const;
            HWIN_EXPORT String Text();

        protected:
            HWIN_EXPORT virtual const MenuItem& InitializeMenuItemInfo(MENUITEMINFO& info) const;
        };

        class SeparatorMenuItem : public MenuItem
        {
        public:
            typedef MenuItem Base;

            HWIN_EXPORT SeparatorMenuItem();
        protected:
            HWIN_EXPORT virtual MenuItem& DoOnAdd();
        };


        class SubMenuItem : public MenuItem
        {
            String text;
            mutable std::shared_ptr<Menu> menu;
        public:
            typedef MenuItem Base;

            HWIN_EXPORT SubMenuItem(const wchar_t* theText);
            HWIN_EXPORT SubMenuItem(const String& theText);

            HWIN_EXPORT std::shared_ptr<Menu> Menu() const;

            HWIN_EXPORT std::shared_ptr<const MenuItems> Items() const;
            HWIN_EXPORT std::shared_ptr<MenuItems> Items();
            
            HWIN_EXPORT SubMenuItem& Add(std::shared_ptr<MenuItem> menuItem);
            HWIN_EXPORT SubMenuItem& Remove(std::shared_ptr<MenuItem> menuItem);

            HWIN_EXPORT std::shared_ptr<TextMenuItem> AddMenuItem(const wchar_t* theText);
            HWIN_EXPORT std::shared_ptr<TextMenuItem> AddMenuItem(const String& theText);

            HWIN_EXPORT std::shared_ptr<SeparatorMenuItem> AddSeparator();

            HWIN_EXPORT std::shared_ptr<SubMenuItem> AddSubMenu(const wchar_t* theText);
            HWIN_EXPORT std::shared_ptr<SubMenuItem> AddSubMenu(const String& theText);

        protected:
            HWIN_EXPORT virtual const MenuItem& InitializeMenuItemInfo(MENUITEMINFO& info) const;
        };




        class MenuItems 
        {
        public:
            typedef std::vector< std::shared_ptr< MenuItem > > vector;
        private:
            friend class Menu;
            Menu* owner;
            vector items;
        public:
            HWIN_EXPORT MenuItems(Menu* theOwner);
            HWIN_EXPORT ~MenuItems( );
            HWIN_EXPORT std::shared_ptr< TextMenuItem > AddMenuItem( const wchar_t* theText );
            HWIN_EXPORT std::shared_ptr< TextMenuItem > AddMenuItem( const String& theText );

            HWIN_EXPORT std::shared_ptr< SeparatorMenuItem> AddSeparator();

            HWIN_EXPORT std::shared_ptr< SubMenuItem > AddSubMenu(const wchar_t* theText);
            HWIN_EXPORT std::shared_ptr< SubMenuItem > AddSubMenu(const String& theText);

            HWIN_EXPORT std::shared_ptr< Menu > Menu() const;
            HWIN_EXPORT MenuItems& Add( std::shared_ptr< MenuItem > menuItem);
            HWIN_EXPORT MenuItems& Remove( std::shared_ptr< MenuItem > menuItem);

            HWIN_EXPORT int IndexOf(std::shared_ptr< const MenuItem> menuItem) const;
            HWIN_EXPORT std::shared_ptr< const MenuItem > Item(int position) const;
            HWIN_EXPORT std::shared_ptr< MenuItem > Item(int position);
        };

        
        class Menu : public Component
        {
            friend class Control;

            static std::map<HMENU,Menu*> menuMap;

            HWIN_EXPORT static void AddToMenuMap(HMENU hMenu, Menu* theMenu);
            HWIN_EXPORT static void RemoveFromMenuMap(HMENU hMenu);
            HWIN_EXPORT static Menu* GetFromMenuMap(HMENU hMenu);
            
            std::shared_ptr<MenuHandle> handle;
            std::shared_ptr<MenuItems> items;

        protected:
            HWIN_EXPORT virtual void DoOnInitMenu(Message& message);
            HWIN_EXPORT virtual void DoOnInitMenuPopup(Message& message);
            HWIN_EXPORT virtual void DoOnMenuCommand(Message& message);

        public:
            typedef Component Base;

            HWIN_EXPORT Menu( std::shared_ptr<MenuHandle> menuHandle );

            HWIN_EXPORT ~Menu( );

            std::shared_ptr<MenuHandle> GetHandle();

            HWIN_EXPORT std::shared_ptr<const MenuItems> Items() const;
            HWIN_EXPORT std::shared_ptr<MenuItems> Items();

            HWIN_EXPORT std::shared_ptr<const MenuItem> Item(int position) const;
            HWIN_EXPORT std::shared_ptr<MenuItem> Item(int position);

            HWIN_EXPORT Menu& AddStyle(DWORD style);

            HWIN_EXPORT Menu& Add(std::shared_ptr<MenuItem> menuItem);
            HWIN_EXPORT Menu& Remove(std::shared_ptr<MenuItem> menuItem);

            HWIN_EXPORT std::shared_ptr<TextMenuItem> AddMenuItem(const wchar_t* theText);
            HWIN_EXPORT std::shared_ptr<TextMenuItem> AddMenuItem(const String& theText);

            HWIN_EXPORT std::shared_ptr<SeparatorMenuItem> AddSeparator();

            HWIN_EXPORT std::shared_ptr<SubMenuItem> AddSubMenu(const wchar_t* theText);
            HWIN_EXPORT std::shared_ptr<SubMenuItem> AddSubMenu(const String& theText);



            boost::signals2::signal<void (Message& message)> OnMenuCommand;
            boost::signals2::signal<void (Message& message)> OnInitMenu;
            boost::signals2::signal<void (Message& message)> OnInitMenuPopup;
        };

        class MenuBar : public Menu
        {
            HWIN_EXPORT static std::shared_ptr<MenuHandle> CreateHandle();
        public:
            typedef Menu Base;

            HWIN_EXPORT MenuBar( );

        };

        enum class PopupMenuAlignment : int
        {
            Left = 0x0000,
            Center = 0x0004,
            Right = 0x0008,
            Top = 0x0000,
            VerticalCenter = 0x0010,
            Bottom = 0x0020
        };
        DEFINE_ENUM_FLAG_OPERATORS(PopupMenuAlignment)


        class PopupMenu : public Menu
        {
            HWIN_EXPORT static std::shared_ptr<MenuHandle> CreateHandle();
            PopupMenuAlignment alignment;
            static PopupMenuAlignment GetDefaultAlignment();
        public:
            typedef Menu Base;

            HWIN_EXPORT PopupMenu( );
            
            HWIN_EXPORT PopupMenuAlignment Alignment() const;
            HWIN_EXPORT PopupMenu& SetAlignment(PopupMenuAlignment theAlignment);

            HWIN_EXPORT PopupMenu& Show(std::shared_ptr<Control> theControl, const POINT& screenPosition);
            HWIN_EXPORT PopupMenu& Show(std::shared_ptr<Control> theControl, const POINT& screenPosition, const RECT& excludeArea);


        };



    };
};

#endif // __HWINMENU_H__
